package com.niiwoo.civet.trade.listener;


import com.alibaba.fastjson.JSON;
import com.google.common.util.concurrent.RateLimiter;
import com.niiwoo.civet.trade.constant.MqConstant;
import com.niiwoo.civet.trade.dto.newRefund.RefundCompensatoryDTO;
import com.niiwoo.civet.trade.dto.newRefund.RefundRepaymentDTO;
import com.niiwoo.civet.trade.service.local.newRefund.dispatch.RefundHelperLocalService;
import com.niiwoo.tripod.provider.exception.BizException;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.IOException;

/**
 * 还款相关监听
 * @author wangjun
 */
@Slf4j
@Component
public class RefundListener
{

    @Autowired
    private RefundHelperLocalService refundHelperLocalService;

    //@Value("${withholdRateLimiterCount}")
    private Integer rateLimiterCount = 2;

    //代扣令牌桶，允许每秒向存管发送rateLimiterCount次代扣请求
    private static RateLimiter rateLimiter;


    @PostConstruct
    public void init(){
        log.info("TradewithholdRateLimiterCount is {}", rateLimiterCount);
        rateLimiter = RateLimiter.create(rateLimiterCount);
    }

    protected void doAckAnwser(Message message, Channel channel,boolean isAck) throws IOException
    {
        if (isAck) {
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } else {
            channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
        }
    }


    /**
     * 部分划扣事件
     * @param message
     * @param channel
     */
    @RabbitListener(queues = {MqConstant.REFUNDNEW_PARTIAL_QUEUE})
    public void partialRefund(Message message, Channel channel) throws IOException
    {
        //应答标记
        Boolean isAck = true;
        RefundRepaymentDTO repaymentDTO = null;
        try
        {
            //从消息中取出消息
            repaymentDTO = JSON.parseObject(new String(message.getBody(), "UTF-8"),RefundRepaymentDTO.class);
            refundHelperLocalService.partialRefund(repaymentDTO);
        }
        catch (BizException | IllegalArgumentException e )
        {
            log.error("RefundListener ->partialRefund BizException,userId={}", repaymentDTO.getUserId(),e);
        }
        catch (Exception e)
        {
            log.error("RefundListener ->partialRefund exception,userId={}",repaymentDTO.getUserId(), e);
            isAck = false;
            try
            {
                Thread.sleep(5 * 1000L);
            } catch (Exception expect) {}
        }
        finally
        {
            doAckAnwser(message,channel,isAck);
        }

    }
    /**
     * 全额划扣事件
     * @param message
     * @param channel
     */
    @RabbitListener(queues = {MqConstant.REFUNDNEW_FULL_QUEUE})
    public void fullRefund(Message message, Channel channel)throws IOException
    {
        //应答标记
        Boolean isAck = true;
        RefundRepaymentDTO repaymentDTO = null;
        try
        {
            //从消息中取出消息
            repaymentDTO = JSON.parseObject(new String(message.getBody(), "UTF-8"),RefundRepaymentDTO.class);
            refundHelperLocalService.fullRefund(repaymentDTO);
        }
        catch (BizException | IllegalArgumentException e )
        {
            log.error("RefundListener ->fullRefund BizException,userId={}", repaymentDTO.getUserId(),e);
        }
        catch (Exception e)
        {
            log.error("RefundListener ->fullRefund exception,userId={}",repaymentDTO.getUserId(), e);
            isAck = false;
            try
            {
                Thread.sleep(5 * 1000L);
            } catch (Exception expect) {}
        }
        finally
        {
            doAckAnwser(message,channel,isAck);
        }

    }

    /**
     * 垫付事件
     * @param message
     * @param channel
     */
    @RabbitListener(queues = {MqConstant.REFUNDNEW_COMPENSATORY_QUEUE})
    public void compensatoryRefund(Message message, Channel channel)throws IOException
    {
        //应答标记
        Boolean isAck = true;
        RefundCompensatoryDTO compensatoryDTO = null;
        try
        {
            //从消息中取出消息
            compensatoryDTO = JSON.parseObject(new String(message.getBody(), "UTF-8"),RefundCompensatoryDTO.class);
            refundHelperLocalService.compensatoryRefund(compensatoryDTO);
        }
        catch (BizException | IllegalArgumentException e )
        {
            log.error("RefundListener ->compensatoryRefund BizException,projectId={}", compensatoryDTO.getProjectId(),e);
        }
        catch (Exception e)
        {
            log.error("RefundListener ->compensatoryRefund exception,projectId={}", compensatoryDTO.getProjectId(),e);
            isAck = false;
            try
            {
                Thread.sleep(5 * 1000L);
            } catch (Exception expect) {}
        }
        finally
        {
            doAckAnwser(message,channel,isAck);
        }

    }

    /**
     * 自动充值(代扣)事件
     * @param message
     * @param channel
     */
    @RabbitListener(queues = {MqConstant.REFUNDNEW_WITHHOLD_QUEUE})
    public void withhold(Message message, Channel channel)throws IOException
    {
        rateLimiter.acquire();
        //应答标记
        Boolean isAck = true;
        RefundRepaymentDTO repaymentDTO = null;
        try
        {
            //从消息中取出消息
            repaymentDTO = JSON.parseObject(new String(message.getBody(), "UTF-8"),RefundRepaymentDTO.class);
            refundHelperLocalService.withhold(repaymentDTO);
        }
        catch (BizException | IllegalArgumentException e )
        {
            log.error("RefundListener ->withhold BizException,userId={}", repaymentDTO.getUserId(),e);
        }
        catch (Exception e)
        {
            log.error("RefundListener ->withhold exception,userId={}", repaymentDTO.getUserId(),e);
            isAck = false;
            try
            {
                Thread.sleep(5 * 1000L);
            } catch (Exception expect) {}
        }
        finally
        {
            doAckAnwser(message,channel,isAck);
        }

    }

    /**
     * 逾期50天代扣事件
     *
     * @param message
     * @param channel
     */
    @RabbitListener(queues = {MqConstant.WITHHOLD_OVERDUE_50_DAY_QUEUE})
    public void withholdOverdue50DayQueue(Message message, Channel channel) throws IOException {
        rateLimiter.acquire();
        //应答标记
        Boolean isAck = true;
        RefundRepaymentDTO repaymentDTO = null;
        try {
            //从消息中取出消息
            repaymentDTO = JSON.parseObject(new String(message.getBody(), "UTF-8"), RefundRepaymentDTO.class);
            refundHelperLocalService.withholdForOverdue50Day(repaymentDTO);
        } catch (BizException | IllegalArgumentException e) {
            log.error("RefundListener ->withholdOverdue50DayQueue BizException,userId={}", repaymentDTO.getUserId(), e);
        } catch (Exception e) {
            log.error("RefundListener ->withholdOverdue50DayQueue exception,userId={}", repaymentDTO.getUserId(), e);
//            isAck = false;
//            try {
//                Thread.sleep(5 * 1000L);
//            } catch (Exception expect) {
//            }
        } finally {
            doAckAnwser(message, channel, isAck);
        }

    }

    /**
     * 逾期50天代扣成功后 requeue事件
     *
     * @param message
     * @param channel
     */
    @RabbitListener(queues = {MqConstant.WITHHOLD_OVERDUE_50_DAY_SUCCESS_QUEUE})
    public void withholdOverdue50DaySuccessQueue(Message message, Channel channel) throws IOException {
        rateLimiter.acquire();
        //应答标记
        Boolean isAck = true;
        RefundRepaymentDTO repaymentDTO = null;
        try {
            //从消息中取出消息
            repaymentDTO = JSON.parseObject(new String(message.getBody(), "UTF-8"), RefundRepaymentDTO.class);
            refundHelperLocalService.withholdForOverdue50Day(repaymentDTO);
        } catch (BizException | IllegalArgumentException e) {
            log.error("RefundListener ->withholdOverdue50DaySuccessQueue BizException,userId={}", repaymentDTO.getUserId(), e);
        } catch (Exception e) {
            log.error("RefundListener ->withholdOverdue50DaySuccessQueue exception,userId={}", repaymentDTO.getUserId(), e);
//            isAck = false;
//            try {
//                Thread.sleep(5 * 1000L);
//            } catch (Exception expect) {
//            }
        } finally {
            doAckAnwser(message, channel, isAck);
        }

    }
}
